package cn.sc.summer.mybatis.strategy.postgresql;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.sc.summer.mybatis.enums.DataSourceTypeEnum;
import cn.sc.summer.mybatis.model.TableBaseConfig;
import cn.sc.summer.mybatis.model.TableFieldXInfo;
import cn.sc.summer.mybatis.model.TableXInfo;
import cn.sc.summer.mybatis.strategy.basestage.Event;
import cn.sc.summer.mybatis.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 类名：pgsql表信息更新操作
 *
 * @author a-xin
 * @date 2024/8/29 11:00
 */
@Slf4j
@Service
public class PgsqlEvent extends Event {

    private static final long serialVersionUID = -5515045841432778229L;

    /**
     * 新增表信息
     *
     * @param tableBaseXInfo 表数据信息
     */
    @Override
    public void addTable(List<? extends TableXInfo> tableBaseXInfo) {
        if (CollUtil.isNotEmpty(tableBaseXInfo)) {
            TableBaseConfig tableConfig = getTableConfig();
            tableBaseXInfo.stream().forEach(tableXInfo -> {
                List<TableFieldXInfo> tableFieldXInfos = tableXInfo.getTableFieldXInfos();
                List<String> primary = new ArrayList<>();
                String fieldSql = tableFieldXInfos.stream().map(tableFieldXInfo -> {
                    if (tableFieldXInfo.getPrimary()) {
                        primary.add(tableFieldXInfo.getFieldName());
                    }
                    return sqlUtil.getFieldSql(tableFieldXInfo.getFieldName(),
                            tableFieldXInfo.getFieldType(),
                            "",
                            tableFieldXInfo.getNullable());
                }).collect(Collectors.joining(","));

                String tableAddSql = sqlUtil.getTableAddSql(tableXInfo.getTableName(), fieldSql, primary, tableXInfo.getComment(), tableConfig);
                super.jdbcTemplate.update(tableAddSql);
                super.print(tableXInfo.getTableName(), tableAddSql);

                tableFieldXInfos.stream().filter(item -> CharSequenceUtil.isNotBlank(item.getComment()))
                        .map(item -> getColumnAddCommentSql(item.getTableName(), item.getFieldName(), item.getComment()))
                        .forEach(item -> {
                            super.jdbcTemplate.update(item);
                            print(item);
                        });

            });
        }
    }

    /**
     * 新增表字段信息
     *
     * @param tableFieldXInfo 表字段信息
     */
    public void addColumn(List<? extends TableFieldXInfo> tableFieldXInfo) {
        if (CollUtil.isNotEmpty(tableFieldXInfo)) {
            tableFieldXInfo.stream().forEach(tableField -> {
                String tableName = tableField.getTableName();
                String fieldSql = sqlUtil.getFieldSql(tableField.getFieldName(),
                        tableField.getFieldType(),
                        "",
                        tableField.getNullable());
                String fieldAddSql = sqlUtil.getFieldAddSql(tableName, fieldSql);
                super.print(tableName, fieldAddSql);
                super.jdbcTemplate.update(fieldAddSql);
                if (CharSequenceUtil.isNotBlank(tableField.getComment())) {
                    String columnCommentSql = getColumnAddCommentSql(tableName, tableField.getFieldName(), tableField.getComment());
                    super.print(tableName, columnCommentSql);
                    super.jdbcTemplate.update(columnCommentSql);
                }
            });
        }
    }

    /**
     * 更新表字段信息
     *
     * @param tableFieldXInfo 表字段信息
     */
    public void updateColumn(List<? extends TableFieldXInfo> tableFieldXInfo) {
        if (CollUtil.isNotEmpty(tableFieldXInfo)) {
            tableFieldXInfo.stream().forEach(tableField -> {
                String tableName = tableField.getTableName();
                String fieldName = tableField.getFieldName();
                String columnNullUpdateSql = getColumnNullUpdateSql(tableName, fieldName, tableField.getNullable());
                String columnTypeUpdateSql = getColumnTypeUpdateSql(tableName, fieldName, tableField.getFieldType());
                this.print(tableName, columnNullUpdateSql);
                this.print(tableName, columnTypeUpdateSql);
                this.jdbcTemplate.update(columnNullUpdateSql);
                this.jdbcTemplate.update(columnTypeUpdateSql);
                if (CharSequenceUtil.isNotBlank(tableField.getComment())) {
                    String columnAddCommentSql = getColumnAddCommentSql(tableName, fieldName, tableField.getComment());
                    this.print(tableName, columnAddCommentSql);
                    this.jdbcTemplate.update(columnAddCommentSql);
                }
            });
        }
    }

    /**
     * 获取表字段注释更新sql
     *
     * @param tableName  表名
     * @param columnName 字段名
     * @param comment    注释信息
     * @return 执行sql
     */
    private String getColumnAddCommentSql(String tableName, String columnName, String comment) {
        return "COMMENT ON COLUMN \"" + tableName + "\".\"" + columnName + "\" IS " + "'" + comment + "';";
    }

    /**
     * 获取表字段类型更新sql
     *
     * @param tableName  表名
     * @param columnName 字段名
     * @param fieldType    字段类型
     * @return 执行sql
     */
    private String getColumnTypeUpdateSql(String tableName, String columnName, String fieldType) {
        return "ALTER TABLE \"" + tableName + "\" ALTER COLUMN \"" + columnName + "\" TYPE " + fieldType + ";";
    }

    /**
     * 获取表字段空值更新sql
     *
     * @param tableName  表名
     * @param columnName 字段名
     * @param nullAble    可否为空
     * @return 执行sql
     */
    private String getColumnNullUpdateSql(String tableName, String columnName, Boolean nullAble) {
        return "ALTER TABLE \"" + tableName + "\" ALTER COLUMN \"" + columnName + "\" " + (nullAble ? "DROP" : "SET") + " NOT NULL;";
    }

    /**
     * 确定该枚举类支持的数据源类型
     *
     * @return 支持的数据源类型
     */
    @Override
    public String supports() {
        return DataSourceTypeEnum.POSTGRESQL.getType();
    }

}
